﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Globalization;

namespace D20.Entities.Characters
{
    /// <summary>
    /// A character's alignment.
    /// </summary>
    public class Alignment
    {
        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:Alignment"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:Alignment"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:Alignment"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            if (obj is Alignment)
            {
                Alignment a = (Alignment)obj;
                return lawful == a.lawful && good == a.good ;
            }
            return false;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="Alignment"/> class.
        /// </summary>
        public Alignment()
        {

        }
        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return lawful.GetHashCode() ^ good.GetHashCode();
        }
        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:Alignment"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:Alignment"/>.
        /// </returns>
        public override string ToString()
        {
            return String.Format(CultureInfo.CurrentCulture, "Lawful: {0}; Good: {1}", lawful, good);
        }
        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="left">The left.</param>
        /// <param name="right">The right.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator ==(Alignment left, Alignment right)
        {
            bool leftNull = Object.ReferenceEquals(left, null);
            bool rightNull = Object.ReferenceEquals(right, null);
            //bool bothNull = leftNull && rightNull;
            //if (bothNull)
            //{
            //    return true;
            //}
            
            if (leftNull || rightNull)
            {
                return false;
            }
            return left.good == right.good && left.lawful == right.lawful;
        }
        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="left">The left.</param>
        /// <param name="right">The right.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator !=(Alignment left, Alignment right)
        {
            return !(left == right);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Alignment"/> class.
        /// </summary>
        /// <param name="lawful">The lawful.</param>
        /// <param name="good">The good.</param>
        public Alignment(float lawful, float good)
        {
            Debug.Assert(lawful <= MaxAlignment, String.Format(CultureInfo.CurrentCulture, "lawful <= MaxAlignment ({0})", MaxAlignment));
            Debug.Assert(lawful >= -MaxAlignment, String.Format(CultureInfo.CurrentCulture, "lawful >= -MaxAlignment (-{0})", MaxAlignment));
            if (lawful > MaxAlignment || lawful < -MaxAlignment)
            {
                throw new ArgumentOutOfRangeException("lawful", String.Format(CultureInfo.CurrentCulture, "Lawful must be between {0} and -{0}.", MaxAlignment));
            }
            this.lawful = lawful;

            Debug.Assert(good <= MaxAlignment, String.Format(CultureInfo.CurrentCulture, "good <= MaxAlignment ({0})", MaxAlignment));
            Debug.Assert(good >= -MaxAlignment, String.Format(CultureInfo.CurrentCulture, "good >= -MaxAlignment (-{0})", MaxAlignment));
            if (lawful > MaxAlignment || lawful < -MaxAlignment)
            {
                throw new ArgumentOutOfRangeException("lawful", String.Format(CultureInfo.CurrentCulture, "Good must be between {0} and -{0}.", MaxAlignment));
            }
            this.good = good;
        }
        /// <summary>
        /// The maximum strength of an alignment.
        /// </summary>
        public const float MaxAlignment = 100f;

        private float lawful;
        private float good;
        /// <summary>
        /// Gets or sets the creature's lawful-chaotic alignment.
        /// </summary>
        /// <value>The lawfulness.</value>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown when the value isn't between the max alignments.</exception>
        public float Lawful
        {
            get { return lawful; }
            set
            {
                            Debug.Assert(value <= MaxAlignment, String.Format(CultureInfo.CurrentCulture, "value <= MaxAlignment ({0})", MaxAlignment));
            Debug.Assert(value >= -MaxAlignment, String.Format(CultureInfo.CurrentCulture, "value >= -MaxAlignment (-{0})", MaxAlignment));
            if (value > MaxAlignment || value < -MaxAlignment)
            {
                throw new ArgumentOutOfRangeException("value", String.Format(CultureInfo.CurrentCulture, "Value must be between {0} and -{0}.", MaxAlignment));
            }
            lawful = value;
            }
        }

        /// <summary>
        /// Gets or sets the creature's good-evil alignment.
        /// </summary>
        /// <value>The goodness.</value>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown when the value isn't between the max alignments.</exception>
        public float Good
        {
            get { return good; }
            set
            {
                Debug.Assert(value <= MaxAlignment, String.Format(CultureInfo.CurrentCulture, "value <= MaxAlignment ({0})", MaxAlignment));
                Debug.Assert(value >= -MaxAlignment, String.Format(CultureInfo.CurrentCulture, "value >= -MaxAlignment (-{0})", MaxAlignment));
                if (value > MaxAlignment || value < -MaxAlignment)
                {
                    throw new ArgumentOutOfRangeException("value", String.Format(CultureInfo.CurrentCulture, "Value must be between {0} and -{0}.", MaxAlignment));
                }
                good = value;
            }
        }

    }
}
